#include "devinsight.h"



#define LW_FLAG_HAS_WAITERS ((uint64)1LU << 30 << 32)

#define LW_FLAG_RELEASE_OK ((uint64)1LU << 29 << 32)
#define LW_FLAG_LOCKED ((uint64)1LU << 28 << 32)
#define LW_VAL_EXCLUSIVE (((uint64)1LU << 24 << 32) + (1LU << 47) + (1LU << 39) + (1LU << 31) + (1LU << 23) + (1LU << 15) + (1LU << 7))
#define LW_VAL_SHARED 1
#define LW_LOCK_MASK ((uint64)((1LU << 25 << 32) - 1))



const char* dviLWLock(LWLock* lock)
{
    if (lock == NULL) {
        return "wrong input, NULL.";
    }
    StringInfoData res;
    initStringInfo(&res);
    uint64 state = pg_atomic_read_u64(&lock->state);

    appendStringInfo(&res, "Tranche Id: %u\n", lock->tranche);
    appendStringInfo(&res, "State: %lu [%s]\n", state, bx64b((void*)&state));
    appendStringInfo(&res, "\t63b-LW_FLAG_HAS_WAITERS: %s\n", (state & LW_FLAG_HAS_WAITERS) ? "true" : "false");
    appendStringInfo(&res, "\t62b-LW_FLAG_RELEASE_OK: %s\n", (state & LW_FLAG_RELEASE_OK) ? "true" : "false");
    appendStringInfo(&res, "\t61b-LW_FLAG_LOCKED: %s\n", (state & LW_FLAG_LOCKED) ? "true" : "false");
    appendStringInfo(&res, "\t57 8:48:8b-LW_VAL_EXCLUSIVE: %s\n", (state & LW_VAL_EXCLUSIVE) ? "true" : "false");
    for (int i = 5; i >=0 ; i--) {
        uint8 partnum = (uint8)((state >> (i * 8)) & 0xff);
        appendStringInfo(&res, "\t%d-%db: %s [%s, %u]\n",
            (i * 8 + 8), (i * 8 + 1),
            bx8b((void*)&partnum),
            (partnum & 0x80) ? "EXCLUSIVE" : "SHARED",   // 最高一位表示是否被占了独锁
            (partnum & 0x7F)                             // 其他七位表示S锁数量
        );
    }

    dlist_mutable_iter iter;
    int i = 0;
    appendStringInfo(&res, "Waiters:\n");
    dlist_foreach_modify(iter, &lock->waiters) {
        PGPROC *proc = dlist_container(PGPROC, lwWaitLink, iter.cur);
        appendStringInfo(&res, "\t%d| tid:%lu  sessid:%lu  wait-mode:%s\n",
            i++,
            proc->pid,
            proc->sessionid,
            proc->lwWaitMode == LW_SHARED ? "LW_SHARED" : "LW_EXCLUSIVE"
        );
    }
    return (const char*)res.data;
}


PG_FUNCTION_INFO_V1(lwlocktest);
extern "C" Datum lwlocktest(PG_FUNCTION_ARGS);
Datum lwlocktest(PG_FUNCTION_ARGS)
{
    LWLock *lock = NodeTableLock;
    if (LWLockHoldByMe(lock)) {
        PG_RETURN_CSTRING("already hold by me.");
    }

    int mode = PG_GETARG_INT32(0);
    if (mode == 2) {
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire X.  lock detail\n%s", dviLWLock(lock))));
        LWLockAcquire(lock, LW_EXCLUSIVE);
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire get X.  lock detail\n%s", dviLWLock(lock))));
        PG_RETURN_CSTRING("LWLockAcquire EXCLUSIVE");
    } else if (mode == 1) {
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire S.  lock detail\n%s", dviLWLock(lock))));
        LWLockAcquire(lock, LW_SHARED);
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire get S.  lock detail\n%s", dviLWLock(lock))));
        PG_RETURN_CSTRING("LWLockAcquire SHARED");
    } else if (mode == 0) {
        ereport(LOG, (errmsg("carrotflag: LWLockRelease lock detail\n%s", dviLWLock(lock))));
        LWLockRelease(lock);
        ereport(LOG, (errmsg("carrotflag: LWLockRelease done, lock detail\n%s", dviLWLock(lock))));
        PG_RETURN_CSTRING("LWLockRelease");
    }

    PG_RETURN_CSTRING("NodeTableLock。 0：R， 1：S， 2：X");
}




PG_FUNCTION_INFO_V1(lwlocktest1);
extern "C" Datum lwlocktest1(PG_FUNCTION_ARGS);
Datum lwlocktest1(PG_FUNCTION_ARGS)
{
    static LWLock* dvi_buff_content_lock = NULL;
    if (dvi_buff_content_lock == NULL) {
        dvi_buff_content_lock = (LWLock*)malloc(sizeof(LWLock));
        LWLockInitialize(dvi_buff_content_lock, LWTRANCHE_BUFFER_CONTENT);
        PG_RETURN_CSTRING("fake dvi_buff_content_lock init done");
    }

    LWLock *lock = dvi_buff_content_lock;
    if (LWLockHoldByMe(lock)) {
        PG_RETURN_CSTRING("already hold by me.");
    }

    int mode = PG_GETARG_INT32(0);
    if (mode == 2) {
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire X.  lock detail\n%s", dviLWLock(lock))));
        LWLockAcquire(lock, LW_EXCLUSIVE);
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire get X.  lock detail\n%s", dviLWLock(lock))));
        PG_RETURN_CSTRING("LWLockAcquire EXCLUSIVE");
    } else if (mode == 1) {
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire S.  lock detail\n%s", dviLWLock(lock))));
        LWLockAcquire(lock, LW_SHARED);
        ereport(LOG, (errmsg("carrotflag: LWLockAcquire get S.  lock detail\n%s", dviLWLock(lock))));
        PG_RETURN_CSTRING("LWLockAcquire SHARED");
    } else if (mode == 0) {
        ereport(LOG, (errmsg("carrotflag: LWLockRelease lock detail\n%s", dviLWLock(lock))));
        LWLockRelease(lock);
        ereport(LOG, (errmsg("carrotflag: LWLockRelease done, lock detail\n%s", dviLWLock(lock))));
        PG_RETURN_CSTRING("LWLockRelease");
    }

    PG_RETURN_CSTRING("NodeTableLock。 0：R， 1：S， 2：X");
}



